package com.BinarySheep.eTools;

import java.text.DecimalFormat;

import android.app.Activity;
import android.app.AlertDialog;
import android.content.Context;
import android.os.Bundle;
import android.os.Handler;
import android.os.Message;
import android.view.KeyEvent;
import android.view.Menu;
import android.view.MenuInflater;
import android.view.MenuItem;
import android.view.View;
import android.view.inputmethod.InputMethodManager;
import android.widget.AdapterView;
import android.widget.ArrayAdapter;
import android.widget.EditText;
import android.widget.Spinner;
import android.widget.TextView;

public class Resistor extends Activity {
	
	private static double MAX_RESISTOR = 99000000000L;
	private static double MIN_RESISTOR = 0.01;
	
	// ResistorView handle
	private ResistorView mResistorView = null;
	
	// Handle to interface elements
	private TextView mResVal = null;
	private TextView mTolval = null;
	private EditText mValue = null;
	private Spinner mMultiplier = null;
	private Spinner mTolerance = null;
	private Spinner mBandmode = null;
	

	@Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.resistor);
        
        // Get handle to ResistorView
        mResistorView = (ResistorView)findViewById(R.id.resistorview);
        mResistorView.updateHandler = resistorViewUpdateHandler;
        
        // Get handle to resval TextView
        mResVal = (TextView)findViewById(R.id.resval);

        // Get handle to tolval TextView
        mTolval = (TextView)findViewById(R.id.tolval);
        
        // Get handle to value EditText
        mValue = (EditText)findViewById(R.id.value);
        mValue.setOnKeyListener(textValueListener);
        
        // Setup multiplier spinner
        mMultiplier = (Spinner)findViewById(R.id.multiplier);
        ArrayAdapter adapter = ArrayAdapter.createFromResource(
        		this, R.array.multipliers, android.R.layout.simple_spinner_item);
        adapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);
        mMultiplier.setAdapter(adapter);
        mMultiplier.setOnItemSelectedListener(spnMultiplierListener);
        
        // Setup tolerance spinner
        mTolerance = (Spinner)findViewById(R.id.tolerance);
        adapter = ArrayAdapter.createFromResource(
        		this, R.array.tolerances, android.R.layout.simple_spinner_item);
        adapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);
        mTolerance.setAdapter(adapter);
        mTolerance.setOnItemSelectedListener(spnToleranceListener);

        // Setup bandmode spinner
        mBandmode = (Spinner)findViewById(R.id.bandmode);
        adapter = ArrayAdapter.createFromResource(
        		this, R.array.bandmodes, android.R.layout.simple_spinner_item);
        adapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);
        mBandmode.setAdapter(adapter);
        mBandmode.setOnItemSelectedListener(spnBandmodeListener);
    }
    
    @Override
    public boolean onCreateOptionsMenu(Menu menu) {
    	boolean result = super.onCreateOptionsMenu(menu);
    	MenuInflater inflater = getMenuInflater();
    	inflater.inflate(R.menu.menu_resistor, menu);
    	return result;
    }
    
    public boolean onOptionsItemSelected(MenuItem item) {
    	switch (item.getItemId()) {
    	case R.id.tools:
    		finish();
    		return true;
    	case R.id.about:
    		showAbout();
    		return true;
    	case R.id.help:
    		showHelp();
    		return true;
    	}
    	return super.onOptionsItemSelected(item);
    }

    protected void showHelp() {
        View messageView = getLayoutInflater().inflate(R.layout.help_resistor, null, false);
        AlertDialog.Builder builder = new AlertDialog.Builder(this);
        builder.setTitle(R.string.help_resistor_title);
        builder.setView(messageView);
        builder.setPositiveButton("Done", null);
        builder.create();
        builder.show();
    }
    
    protected void showAbout() {
        // Inflate the about message contents
        View messageView = getLayoutInflater().inflate(R.layout.about, null, false);
        
        // When linking text, force to always use default color. This works
        // around a pressed color state bug.
        TextView textView = (TextView) messageView.findViewById(R.id.about_credits);
        int defaultColor = textView.getTextColors().getDefaultColor();
        textView.setTextColor(defaultColor);
        
        AlertDialog.Builder builder = new AlertDialog.Builder(this);
        
        builder.setIcon(R.drawable.icon);
        builder.setTitle(R.string.app_name_short);
        builder.setView(messageView);
        builder.setPositiveButton("Done", null);
        builder.create();
        builder.show();
    }   
    
    // Value TextView handler
    private View.OnKeyListener textValueListener =
    	new View.OnKeyListener() {
    	public boolean onKey(View v, int keyCode, KeyEvent event) {
    		if (keyCode == KeyEvent.KEYCODE_PERIOD) {
    			// See if a decimal already exists
    			String tmp = mValue.getText().toString();
    			int cnt = 0;
    			for (int i = 0; i < tmp.length(); i++) {
    				if (tmp.charAt(i) == '.' && cnt++ > 0) 
    					return true;
    			}
    		}
			SetBands();
			return false;
    	}
    };
    
    // Multiplier Spinner handler
	private Spinner.OnItemSelectedListener spnMultiplierListener =
		new Spinner.OnItemSelectedListener() {
		public void onItemSelected(AdapterView parent, View v, int position, long id) {
			SetBands();
		}
		public void onNothingSelected(AdapterView parent) { }
	};
	
    // Tolerance Spinner handler
	private Spinner.OnItemSelectedListener spnToleranceListener =
		new Spinner.OnItemSelectedListener() {
		public void onItemSelected(AdapterView parent, View v, int position, long id) {
			SetBands();
		}
		public void onNothingSelected(AdapterView parent) { }
	};
	
    // Bandmode Spinner handler
	private Spinner.OnItemSelectedListener spnBandmodeListener =
		new Spinner.OnItemSelectedListener() {
		public void onItemSelected(AdapterView parent, View v, int position, long id) {
			int index = parent.getSelectedItemPosition();			
			if (index == 0)
				mResistorView.SetBandMode(mResistorView.BAND_MODE_4);
			else if (index == 1)
				mResistorView.SetBandMode(mResistorView.BAND_MODE_5);
			SetBands();
		}
		public void onNothingSelected(AdapterView parent) { }
	};    
	
	// ResistorView updateHandler
	private Handler resistorViewUpdateHandler = new Handler() {
		public void handleMessage(Message msg) {
			// Close the virtual keyboard if its open
			InputMethodManager inputManager = 
				(InputMethodManager)Resistor.this.getSystemService(Context.INPUT_METHOD_SERVICE);
			inputManager.hideSoftInputFromWindow(mValue.getWindowToken(),
					InputMethodManager.HIDE_NOT_ALWAYS);
			
			// Update mResVal with bands selection, don't update UI 
			int index = 0;
			float value = 0;
			int mult = 0;
			
			// Get band mode
			int bandMode = mResistorView.bandMode;
			
			// Significant figure bands
			if (mResistorView.bandMode == mResistorView.BAND_MODE_5)
				value += mResistorView.bands[index++] * 100;
			value += mResistorView.bands[index++] * 10;
			value += mResistorView.bands[index++];

			// Multiplier band
			int tmp = mResistorView.bands[index++];
			if (tmp > 9) { // Ohm - small values
				mult = 0;
				value *= 1.0 / (Math.pow(10, tmp - 9));
			} else if (tmp > 7 || (bandMode == mResistorView.BAND_MODE_5 && tmp > 6)) { 
				// GOhm
				mult = 3;
				value *= Math.pow(10, tmp - 9);
			} else if (tmp > 4 || (bandMode == mResistorView.BAND_MODE_5 && tmp > 3)) { 
				// MOhm
				mult = 2;
				value *= Math.pow(10, tmp - 6);
			} else if (tmp > 1 || (bandMode == mResistorView.BAND_MODE_5 && tmp > 0)) { 
				// KOhm
				mult = 1;
				value *= Math.pow(10, tmp - 3);
			} else { // Ohm - normal values
				mult = 0;
				value *= Math.pow(10, tmp);
			}
			
			// Update mResVal
			String sFinal = String.valueOf(value);
			if (mult == 1)
				sFinal += "K";
			if (mult == 2)
				sFinal += "M";
			if (mult == 3)
				sFinal += "G";
			sFinal += "\u2126";
			mResVal.setText(sFinal);
			
			// Update tolerance display
			// Set top tolerance display
			int tol = mResistorView.bands[index++];
			switch (tol) {
			case 1:
				mTolval.setText("\u00B11%");
				break;
			case 2:
				mTolval.setText("\u00B12%");
				break;
			case 5:
				mTolval.setText("\u00B10.5%");
				break;
			case 6:
				mTolval.setText("\u00B10.25%");
				break;
			case 7:
				mTolval.setText("\u00B10.10%");
				break;
			case 8:
				mTolval.setText("\u00B10.05%");
				break;
			case 10:
				mTolval.setText("\u00B15%");
				break;
			case 11:
				mTolval.setText("\u00B110%");
				break;
			}			
		}
	};
	
	private void InvalidState() {
		// Not a valid resistor value
		mResVal.setText("INVALID");
		mTolval.setText("");
		mResistorView.Clear();
		mResistorView.Update();
	}
	
	private String StringReplaceAt(String val, String replace, int i) {
		return val.substring(0, i) + replace + val.substring(i + 1);
	}
	
	// Adjusts bands array when a UI element has changed its status
	private void SetBands() {
		Double dVal;
		String sNotVal;
		
		// Get entered resistor value
		String val = mValue.getText().toString();
		
		// Get selected multiplier
		int mult = mMultiplier.getSelectedItemPosition();
		
		// Get selected tolerance
		int tol = mTolerance.getSelectedItemPosition();
		
		// Get band mode
		int bandMode = mResistorView.bandMode;
		
		// Convert entered resistor value 
		DecimalFormat df;
		try {
			// Convert to double
			dVal = Double.parseDouble(val);			

			// Apply selected multiplier
			if (mult == 1)
				dVal *= 1000;
			else if (mult == 2)
				dVal *= 1000000;

			// Convert to sci-notation string
			df = new DecimalFormat("0.00E0");
			sNotVal = df.format(dVal);
		} catch (NumberFormatException e) {
			InvalidState();
			return;
		}
		
		// Is the value too small or too large to calc?
		if (dVal < MIN_RESISTOR || dVal > MAX_RESISTOR) { 
			InvalidState();
			return;						
		}
		
		// Build resistor value string and display
		int exp;
		if (dVal < 1 && dVal != 0) { // is it a negative exponent?
			exp = -1 * (sNotVal.charAt(6) - 0x30); // grab exponent
		} else {
			exp = sNotVal.charAt(5) - 0x30; // grab exponent
			if (sNotVal.length() > 6)
				exp = 10 + (sNotVal.charAt(6) - 0x30);
		}
		int dec = (int)(exp / 3); // figure display decade setup
		exp -= dec * 3; // reduce exponent by multiplier
		String sFinal = String.valueOf(dVal / (Math.pow(1000, dec)));

		// Chop to correct amount of sig digits
		int sigs = bandMode - 2;
		// Update sigs to reflect BLACK in 1st or 2nd band
		if (dVal < 1 && bandMode == mResistorView.BAND_MODE_5)
			sigs--;
		boolean dot = false; // Has decimal been found
		boolean first = false;
		for (int i = 0; i < sFinal.length(); i++) {
			// Find the decimal point
			if (sFinal.charAt(i) == '.') {
				dot = true;
				continue;
			}
			
			// Is fist sig a zero?
			if (!first && sFinal.charAt(i) == '0') {
				// don't count it unless its right of dot
				if (dot)
					sigs--;
				continue;
			}
			
			// Count sigs
			if (sigs <= 0) {
				// All sigs found, is dot found?
				if (dot) {
					// Remove anything right of dot (mark as X, remove later)
					if (sFinal.charAt(i-1) == '.')
						sFinal = StringReplaceAt(sFinal, "0", i);
					else
						sFinal = StringReplaceAt(sFinal, "X", i);
				} else {
					// Zero anything left of dot
					sFinal = StringReplaceAt(sFinal, "0", i);
				}
			} else {
				first = true;
				// Count this sig
				sigs--;
			}
		}
		sFinal = sFinal.replace("X", "");
		
		// Append zeros, multiplier, and Ohm sign
		if (dec == 1)
			sFinal += "K";
		if (dec == 2)
			sFinal += "M";
		if (dec == 3)
			sFinal += "G";
		sFinal += "\u2126";
		mResVal.setText(sFinal);
		
		// Set top tolerance display
		switch (tol) {
		case 0:
			mTolval.setText("\u00B110%");
			break;
		case 1:
			mTolval.setText("\u00B15%");
			break;
		case 2:
			mTolval.setText("\u00B12%");
			break;
		case 3:
			mTolval.setText("\u00B11%");
			break;
		case 4:
			mTolval.setText("\u00B10.5%");
			break;
		case 5:
			mTolval.setText("\u00B10.25%");
			break;
		case 6:
			mTolval.setText("\u00B10.10%");
			break;
		case 7:
			mTolval.setText("\u00B10.05%");
			break;
		}
		
		// Edit bands array
		// Setup for multiplier band
		int index = 0;
		int mutton = 0;
		if (dVal < 1 && dVal != 0) { // is it a negative exponent?
			exp = -1 * (sNotVal.charAt(6) - 0x30); // grab exponent
		} else {
			exp = sNotVal.charAt(5) - 0x30; // grab exponent
			if (sNotVal.length() > 6)
				exp = 10 + (sNotVal.charAt(6) - 0x30);
		}		
		if (bandMode == ResistorView.BAND_MODE_5)
			exp--;
		if (exp > 0)
			mutton = exp - 1;			
		else if (exp == 0)
			mutton = 10;
		else if (exp == -1)
			mutton = 11;
		else if (exp == -2) {
			mutton = 11;
			mResistorView.bands[index++] = 0;
		} else if (exp == -3) {
			mutton = 11;
			mResistorView.bands[index++] = 0;
			mResistorView.bands[index++] = 0;
		}
		
		// Color bands
		for (int i = 0; i < sNotVal.length(); i++) {
			char tmp = sNotVal.charAt(i);			
			// Skip dot
			if (tmp == '.')
				continue;
			
			// Set band color
			mResistorView.bands[index++] = tmp - 0x30;
			
			// Are we done
			if (index >= bandMode - 2)
				break; // sigs set
		}
		
		// Multiplier band
		mResistorView.bands[index++] = mutton;
		
		// Tolerance band
		index = bandMode - 1;
		switch (tol) {
		case 0:
			mResistorView.bands[index] = 11; // silver
			break;
		case 1:
			mResistorView.bands[index] = 10; // gold
			break;
		case 2:
			mResistorView.bands[index] = 2; // red
			break;
		case 3:
			mResistorView.bands[index] = 1; // brown
			break;			
		case 4:
			mResistorView.bands[index] = 5; // green
			break;
		case 5:
			mResistorView.bands[index] = 6; // blue
			break;
		case 6:
			mResistorView.bands[index] = 7; // violet
			break;
		case 7:
			mResistorView.bands[index] = 8; // grey
			break;
		}
		
		// Update ResistorView
		mResistorView.Update();
	}
	
}
